(function(window, undefined) {
	var GeometryHelper = function() {
		this.polygonlist = []; //生成多边形集合
	}; //几何帮助类
	var Intersection = { //判断几何体之间的关系类型
		None: 'None',
		Tangent: 'Tangent',
		Intersection: 'Intersection',
		Containment: 'Containment'
	};
	var Location = { //点与线的位置关系
		over: 0,
		left: 1,
		right: 2
	};

	GeometryHelper.prototype = {
		constructor: GeometryHelper,
		DistancePointToPoint: function(p, a) { //点到点的距离
			var dis = (a[1] - p[1]) * (a[1] - p[1]) + (a[0] - p[0]) * (a[0] - p[0]);
			return dis;
		},
		DistancePointToLine: function(p, p0, p1) { //点到线之间的距离
			var dis = null;
			if(p0.x == p1.x) {
				dis = Math.abs(p1.x - p.x);
			} else {
				var k = -((p0.y - p1.y) / (p0.x - p1.x));
				var b = (p0.y * p1.x - p1.y * p0.x) / (p1.x - p0.x);
				dis = Math.abs(k * p.x + 1 * p.y + b) / Math.sqrt(1 + k * k);
			}
			return dis;
		},
		LocationPointToLine: function(p, p0, p1) { //点相对线的位置 p0p1线段
			var key = (p1[0] - p0[0]) * (p[1] - p0[1]) - (p[0] - p0[0]) * (p1[1] - p0[1]);
			if(key > 0) {
				return Location.left;
			} else if(key == 0) {
				return Location.over;
			} else {
				return Location.right;
			}
		},
		LocationCenterPolygon: function(polygon, ab) { //判断多边形相对直线位置
			var minx = polygon[0][0],
				miny = polygon[0][1],
				maxx = polygon[0][0],
				maxy = polygon[0][1]; //最小最大点
			for(var i = 0; i < polygon.length; i++) {
				if(polygon[i][0] > maxx) {
					maxx = polygon[i][0];
				}
				if(polygon[i][0] < minx) {
					minx = polygon[i][0];
				}
				if(polygon[i][1] > maxy) {
					maxy = polygon[i][1];
				}
				if(polygon[i][1] < miny) {
					miny = polygon[i][1];
				}
			}
			var centerpoint = [(minx + maxx) / 2, (miny + maxy) / 2]
			return this.LocationPointToLine(centerpoint, ab[0], ab[1]);
		},
		ProjectionPointToLine: function(a, b, c) { //点投影到直线交点，线段ab
			if(a.x == b.x) { //竖线
				return {
					x: a.x,
					y: c.y
				}
			}
			if(a.y == b.y) { //横线
				return {
					x: c.x,
					y: a.y
				}
			}
			var k = (b.y - a.y) / (b.x - a.x); //直线斜率
			var px = ((k * a.x + c.x / k + c.y - a.y) / (1 / k + k));
			var py = (-1 / k * (px - c.x) + c.y);
			return {
				x: px,
				y: py
			}
		},
		IntersectionLineToLine: function(a, b, c, d) { //计算两条线段的交点,若不想交则返回false,ab线段,cd线段
			// 三角形abc 面积的2倍  
			var area_abc = (a[0] - c[0]) * (b[1] - c[1]) - (a[1] - c[1]) * (b[0] - c[0]);
			// 三角形abd 面积的2倍  
			var area_abd = (a[0] - d[0]) * (b[1] - d[1]) - (a[1] - d[1]) * (b[0] - d[0]);
			// 面积符号相同则两点在线段同侧,不相交 (对点在线段上的情况,本例当作不相交处理);  
			if(area_abc * area_abd >= 0) {
				return false;
			}
			// 三角形cda 面积的2倍  
			var area_cda = (c[0] - a[0]) * (d[1] - a[1]) - (c[1] - a[1]) * (d[0] - a[0]);
			// 三角形cdb 面积的2倍  
			// 注意: 这里有一个小优化.不需要再用公式计算面积,而是通过已知的三个面积加减得出.  
			var area_cdb = area_cda + area_abc - area_abd;
			if(area_cda * area_cdb >= 0) {
				return false;
			}
			//计算交点坐标  
			var t = area_cda / (area_abd - area_abc);
			var dx = t * (b[0] - a[0]),
				dy = t * (b[1] - a[1]);
			return new Array(a[0] + dx, a[1] + dy);
		},
		DistancePointToNormalOrg: function(a, b, c) { //点到线段法线原点的距离,ab线段
			var nx = b.y - a.y,
				ny = a.x - b.x;
			var normalLine = {
				x: nx,
				y: ny
			}; //线段ab的发现
			var dist = normalLine.x * c.x + normalLine.y * c.y; //点c在法线上投影位置
			return dist;
		},
		computetop: function(order, sortBy) { //json数组按属性排序
			var ordAlpah = (order == 'asc') ? '>' : '<';
			var sortFun = new Function('a', 'b', 'return a.' + sortBy + ordAlpah + 'b.' + sortBy + '?1:-1');
			return sortFun;
		},
		contains: function(arr, obj) { //JS判断元素是否在数组内
			var i = arr.length;  
			while(i--) {    
				if(arr[i] === obj) {      
					return true;    
				}  
			}  
			return false;
		},
		productpolygon: function(fa, fb) { //线要素要素a,面要素b
			var ab = fa.getGeometry().getCoordinates();
			var cd = fb.getGeometry().getCoordinates();
			var geotype = fb.getGeometry().getType().toUpperCase(); //面要素类型
			
			var leftpolygonset=[];
			var rightpolygonset=[];
			if(geotype == "POLYGON") {
				for(var i = 0; i < cd.length; i++) {
					var polygons = this.clippolygon(ab, cd[i]);
					for(var j = 0; j < polygons.length; j++) {
						var location = this.LocationCenterPolygon(polygons[j], ab);
						if(location == 1) { //左
							if(polygons[j].length) leftpolygonset.push(polygons[j]);
						} else {
							if(polygons[j].length) rightpolygonset.push(polygons[j]);
						}
					}
				}

			} else if(geotype == "MULTIPOLYGON") {
				for(var i = 0; i < cd.length; i++) {
					var leftpolygon = [];
					var rightpolygon = [];
					for(var j = 0; j < cd[i].length; j++) {
						var polygons = this.clippolygon(ab, cd[i][j]);
						for(var k = 0; k < polygons.length; k++) {
							var location = this.LocationCenterPolygon(polygons[k], ab);
							if(location == 1) { //左
								if(polygons[k].length) leftpolygon.push(polygons[k]);
							} else {
								if(polygons[k].length) rightpolygon.push(polygons[k]);
							}
						}
					}
					if(leftpolygon.length) leftpolygonset.push(leftpolygon);
					if(rightpolygon.length) rightpolygonset.push(rightpolygon);
				}

			} else {
				return;
			}
			var leftfeature=null;
			var rightfeature=null;
			if(geotype == "POLYGON") {
				leftfeature=new ol.Feature(new ol.geom.MultiPolygon([leftpolygonset]));
				rightfeature=new ol.Feature(new ol.geom.MultiPolygon([rightpolygonset]));
			}else if(geotype == "MULTIPOLYGON"){
				leftfeature=new ol.Feature(new ol.geom.MultiPolygon(leftpolygonset));
				rightfeature=new ol.Feature(new ol.geom.MultiPolygon(rightpolygonset));
			}
			return {
				lf:leftfeature,
				rf:rightfeature
			}
		},
		packpolygon: function(edgelist) {
			if(!edgelist.length) {
				return;
			}
			var pointlist = [];
			var indexs = [];
			indexs.push(0);
			var start = edgelist[0].startindex;
			var end = edgelist[0].endindex;
			pointlist.push(edgelist[0].start);
			pointlist.push(edgelist[0].end);
			for(var i = 1; i < edgelist.length; i++) {
				for(var j = 1; j < edgelist.length; j++) {
					if(edgelist[j].startindex == end) {
						pointlist.push(edgelist[j].end);
						indexs.push(j);
						end = edgelist[j].endindex;
						if(edgelist[j].endindex == start) {
							this.polygonlist.push(pointlist);
							var newedgelist = [];
							for(var k = 0; k < edgelist.length; k++) {
								if(!this.contains(indexs, k)) {
									newedgelist.push(edgelist[k]);
								}
							}
							this.packpolygon(newedgelist);
						}
					}
				}
			}
		},
		clippolygon: function(ab, cd) {
			this.polygonlist = [];
			var a = ab[0];
			var b = ab[1];
			var intersection = []; //交点
			var vertexList_afterDiv = []; //插入切割点后顶点序列
			var edgeList_afterDiv = []; //插入切割点后的边序列
			var vertexIndexList = []; //插入切割点后的边的顶点索引序列

			for(var i = 0; i < cd.length; i++) {
				var c = [cd[i][0], cd[i][1]];
				var last = i + 1;
				if(i == cd.length - 1) {
					last = 0;
				}
				var d = [cd[last][0], cd[last][1]];
				var result = this.IntersectionLineToLine(a, b, c, d); //计算线段与线段交点
				vertexList_afterDiv.push(c);
				if(result) {
					intersection.push(result);
					vertexList_afterDiv.push(result);
					edgeList_afterDiv.push(new Array(c, result));
					edgeList_afterDiv.push(new Array(result, d));
					vertexIndexList.push(new Array(i, -intersection.length));
					vertexIndexList.push(new Array(-intersection.length, last));
					continue;
				}
				edgeList_afterDiv.push(new Array(c, d));
				vertexIndexList.push(new Array(i, last));
			}
			if(intersection.length == 0) {
				return [cd];
			} else if(intersection.length == 1) {
				return [cd];
			}

			var rightvertexIndexSet = []; //右侧边的顶点索引集合
			var leftvertexIndexSet = []; //左侧边的顶点索引集合

			for(var i = 0; i < edgeList_afterDiv.length; i++) {
				var p0 = edgeList_afterDiv[i][0];
				var p1 = edgeList_afterDiv[i][1];
				var direction0 = this.LocationPointToLine([(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2], a, b);
				if(direction0 == 1) { //左边
					leftvertexIndexSet.push({
						startindex: vertexIndexList[i][0],
						endindex: vertexIndexList[i][1],
						start: edgeList_afterDiv[i][0],
						end: edgeList_afterDiv[i][1]
					});

				} else if(direction0 == 2) { //右边
					rightvertexIndexSet.push({
						startindex: vertexIndexList[i][0],
						endindex: vertexIndexList[i][1],
						start: edgeList_afterDiv[i][0],
						end: edgeList_afterDiv[i][1]
					});
				}
			}

			var newintersection = []; //按照距离起点排序后点集
			for(var i = 0; i < intersection.length; i++) {
				var dis = this.DistancePointToPoint(intersection[i], a);
				newintersection.push({
					point: intersection[i],
					distance: dis,
					index: -(i + 1)
				});
			}
			newintersection.sort(this.computetop('asc', 'distance'));

			var sortedindex = 0;
			for(var i = 0; i < newintersection.length; i++) {
				if(newintersection[i].index == -1) {
					sortedindex = i;
				}
			}

			var leftSideCapSet = []; //左边封口边
			var rightSideCapList = []; //右边封口边

			var leftSideCapIndexSet = []; //左边封口边的顶点索引集合
			var rightSideCapIndexList = []; //右边封口边的顶点索引集合

			var nextpointdirection = 0; //最近交点的下一点相对线段位置
			for(var i = 0; i < vertexIndexList.length; i++) {
				if(vertexIndexList[i][0] == newintersection[0].index) {
					var nextpoint = edgeList_afterDiv[i][1];
					nextpointdirection = this.LocationPointToLine(nextpoint, a, b);
				}
			}
			for(var i = 0; i < newintersection.length; i++) {
				if(i % 2 == 0) {
					if(nextpointdirection == 1) { //
						leftSideCapIndexSet.push({
							startindex: newintersection[i + 1].index,
							endindex: newintersection[i].index,
							start: newintersection[i + 1].point,
							end: newintersection[i].point
						});
						rightSideCapIndexList.push({
							startindex: newintersection[i].index,
							endindex: newintersection[i + 1].index,
							start: newintersection[i].point,
							end: newintersection[i + 1].point
						});
					} else if(nextpointdirection == 2) { //右边
						leftSideCapIndexSet.push({
							startindex: newintersection[i].index,
							endindex: newintersection[i + 1].index,
							start: newintersection[i].point,
							end: newintersection[i + 1].point
						});
						rightSideCapIndexList.push({
							startindex: newintersection[i + 1].index,
							endindex: newintersection[i].index,
							start: newintersection[i + 1].point,
							end: newintersection[i].point
						});
					}
				}
			}

			var rightSideEdgeAndCapIndexSet = rightvertexIndexSet.concat(rightSideCapIndexList);
			var leftSideEdgeAndCapIndexSet = leftvertexIndexSet.concat(leftSideCapIndexSet);
			this.packpolygon(rightSideEdgeAndCapIndexSet.sort(this.computetop('asc', 'startindex')));
			this.packpolygon(leftSideEdgeAndCapIndexSet.sort(this.computetop('asc', 'startindex')));
			return this.polygonlist;
		}
	}
	window["GeometryHelper"] = GeometryHelper
})(this)